// Copyright (C) Calum Grant 2008

namespace dynamic
{
	DYNAMIC_API var create_closure(const var & object, const char * method, const var & fn);

	namespace internal
	{
		template<typename T> class var_member;

		/// Helper methods for var_member.
		/** \ingroup  syntax */
		template<typename T>
		class var_member_base : public var_methods<var_member<T>, var>
		{
		protected:
			var m_object;
			T m_member;

		public:
			var_member_base(const var & object, const T & member) : 
				m_object(object), 
				m_member(member)
			{
			}

			/// Retrieves the member of the object
			var get_var() const 
			{ 
				return m_object.impl().get_member(m_member); 
			}

			/// Called by \ref var_methods to read the var.
			var deref() const { return get_var(); }

			/// Assigns the member of the object.
			void set(const var & v)
			{ 
				m_object.impl().set_member(m_member, v); 
			}

			var_member<const char*> operator[](const char * m) const;
			var_member<int> operator[](int m) const;
			var_member<var> operator[](const var & m) const;

			template<typename U>
			var_member<var> operator[](const var_member_base<U>&m) const;
		};


		/// A member of an object.
		/** The purpose of this is to read and write to members of the object, 
			but you cannot just return a reference as you would in C++.
			This is the result of dynamic::var::operator[]
			\ingroup syntax
		*/
		template<typename T>
		class var_member : public var_member_base<T>
		{
		public:
			var_member(const var & object, const T & member) : 
				var_member_base<T>(object, member)
			{
			}

			var_member & operator=(const var_member & v)
			{ set(v); return *this; }

			template<typename U>
			var_member & operator=(const U & v)
			{ set(v); return *this; }
		};


		/// A const char * member of an object.
		/** Specialise this because some functions only apply to strings.
			(mainly the object-related functions).

			The assignment operator works differently because when you assign 
			a function it creates a method for you.

			\ingroup syntax
			*/
		template<>
		class var_member<const char*> : public var_member_base<const char*>
		{
		public:
			var_member(const var & object, const char * member) : 
				var_member_base<const char*>(object, member)
			{
			}

			var_member & operator=(const var_member & v)
			{ set(v); return *this; }

			template<typename U>
			var_member & operator=(const U & v)
			{ set(v); return *this; }

			var operator++() { return m_object.impl().member_inc(m_member); }
			var operator--() { return m_object.impl().member_dec(m_member); }
			var operator++(int i) { return m_object.impl().member_inc(m_member, i); }
			var operator--(int i) { return m_object.impl().member_dec(m_member, i); }

			var operator+=(const var &v) { return m_object.impl().member_add(m_member,v); }
			var operator-=(const var &v) { return m_object.impl().member_sub(m_member,v); }

			var operator()() { return m_object.impl().member_call(m_member); }

			var operator()(const var & a0) 
			{ return m_object.impl().member_call(m_member,a0); }

			var operator()(const var & a0, const var & a1) 
			{ return m_object.impl().member_call(m_member,a0,a1); }

			var operator()(const var & a0, const var & a1, const var & a2) 
			{ return m_object.impl().member_call(m_member,a0,a1,a2); }

			var operator()(const var & a0, const var & a1, const var & a2, const var & a3) 
			{ return m_object.impl().member_call(m_member,a0,a1,a2,a3); }

			var operator()(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4) 
			{ return m_object.impl().member_call(m_member,a0,a1,a2,a3,a4); }

			var operator()(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5) 
			{ return m_object.impl().member_call(m_member,a0,a1,a2,a3,a4,a5); }

			var operator()(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6) 
			{ return m_object.impl().member_call(m_member,a0,a1,a2,a3,a4,a5,a6); }

			var operator()(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7) 
			{ return m_object.impl().member_call(m_member,a0,a1,a2,a3,a4,a5,a6,a7); }

			var operator()(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8) 
			{ return m_object.impl().member_call(m_member,a0,a1,a2,a3,a4,a5,a6,a7,a8); }

			var operator()(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8, const var & a9) 
			{ return m_object.impl().member_call(m_member,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9); }

			var_member & operator=(f1 fn) 
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f2 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f3 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f4 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f5 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f6 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f7 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f8 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f9 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(f10 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf1 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf2 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf3 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf4 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf5 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf6 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf7 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf8 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf9 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }

			var_member & operator=(vf10 fn)
			{ set(create_closure(m_object, m_member, fn)); return *this; }
		};
	}
}
